<?php
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。JCAT 由中国团队开发维护。
//  正在使用的这个版本是：0.4.1 / SVN信息: $Id: class.JCAT_UICtrlGtkTree.php 1510 2009-03-23 06:51:00Z alee $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [下载(HTTP)] http://code.google.com/p/jcat-php/downloads/list
//    [下载(svn)] svn checkout http://jcat-php.googlecode.com/svn/branches/0.4.0/Framework/ JCAT0.4
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.com/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.com/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/




/**
 * 为 GtkViewTree 提供 JCAT_UICtrlGtk 类
 *
 * @author		alee
 * @access		public
 */
abstract class JCAT_UICtrlGtkTree extends JCAT_UICtrlFormGtkBase
{
	/**
	 * 根据窗体ID 创建一个Gtk窗体		
	 *
	 * @access	public
	 * @param	$sWidgetId		string
	 * @static
	 * @return	GtkWidget
	 */
	static public function CreateWidget($sWidgetId)
	{
		JCAT_ASSERT::ASSERT_(0,JCAT_Language::SentenceEx('无法自动创建 JCAT_UICtrlGtkTree 控件的 窗体，请自行创建窗体对象后，传递给 JCAT_UICtrlGtkTree 的构找函数。','JCAT',null));
	}

	/**
	 * What's this Method ?
	 * 
	 * @access	protected
	 * @param	$wndWidget=null	GtkTreeView	控件主窗体
	 * @return	old_value
	 */
	protected function SetMainWidget(GtkWidget $wndMainWidget=null) 
	{
		JCAT_ASSERT::ASSERT_INSTANCE($wndMainWidget,'GtkTreeView') ;
		
		// 取得已有模型
		$aModel = $this->GetGtkModel() ;
		
		// 设置新窗体
		$old_value = parent::SetMainWidget($wndMainWidget) ;
		
		// 如果模型不存在，创建新模型
		if($aModel===null)
		{
			$aModel = $this->CreateModel() ;
			JCAT_ASSERT::ASSERT_INSTANCE($aModel,'GtkTreeModel' 
					, JCAT_Language::SentenceEx('JCAT_UICtrlGtkTree::CreateModel() 方法必须返回一个 实现 GtkTreeModel 接口的 模型对象。','JCAT',null)) ;
			
			// 保存新模型
			$this->SetGtkModel($aModel) ;
		}
		
		// 初始化 操作
		$this->InitializeColumns() ;
		
		return $old_value ;
	}
	
	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	GtkTreeModel
	 */
	public function GetGtkModel() 
	{
		$wndTree = $this->GetMainWidget() ;
		
		return $wndTree?
			 $wndTree->get_model() :
			 null ;
	}



	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$aModel=null		What's this Parameter ?
	 * @return	old_value
	 */
	public function SetGtkModel( GtkTreeModel $aModel=null ) 
	{
		$wndWidget = $this->GetMainWidget() ;
		JCAT_ASSERT::ASSERT_INSTANCE($wndWidget,'GtkTreeView',JCAT_Language::SentenceEx('UICtrl(%s) 的主窗口尚未初始化。','JCAT',null,$this->GetName())) ;
		
		$old_value = $wndWidget->get_model() ;
				
		// 设置  新的 模型
		$wndWidget->set_model($aModel) ;
				
		return $old_value ;
	}


	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	GtkTreeModel
	 */
	abstract public function CreateModel() ;

	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$aStartItem		GtkTreeIter		what's this
	 * @param	$nLevel			int				what's this
	 * @return	void
	 */
	public function CreateItemIterator($aStartItem=null,$nLevel=0)
	{
		$aModel = $this->GetGtkModel() ;
		JCAT_ASSERT::ASSERT_INSTANCE($aModel,'GtkTreeStore',JCAT_Language::SentenceEx('UI控件：“%s”主窗体尚未创建','JCAT',null,$this->GetName())) ;
		
				return new JCAT_GtkTreeItemIterator($aModel,$aStartItem,$nLevel) ;
	}
	
	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$Value	array	What's this Parameter ?
	 * @return	old_var
	 */
	public function SetDataByExchange( $Value ) 
	{
		JCAT_ASSERT::ASSERT_ARRAY($Value) ;
		
		$aModel = $this->GetGtkModel() ; 
		JCAT_ASSERT::ASSERT_INSTANCE($aModel) ; 
		
		// 清空已有内容
		$aModel->clear();
		
		$this->SetItemData($Value) ;
	}



	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	array
	 */
	public function GetExchangeData(  ) 
	{
		$aModel = $this->GetGtkModel() ;
		JCAT_ASSERT::ASSERT_INSTANCE($aModel) ; 		
		return $this->GetItemData() ;
	}

	
	/**
	 * 
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetDataLength()
	{
		$nRet = 0 ;
		
		$aModel = $this->GetGtkModel() ; 
		if( is_object($aModel) )
		{
			$aIterator = new JCAT_GtkTreeItemIterator($aModel) ;
			$aIterator->First() ;
			while( !$aIterator->IsDone() )
			{
				$nRet ++ ;			
				$aIterator->Next() ;
			}
		}
		
		return $nRet ;
	}
	
	
	
	/**
	 * 返回一个包含 Item 数据的数组
	 * 
	 * @access	public
	 * (@param 	$nParentItem=null	GtkTreeIter		上级 Item
	 * @param 	$sChildElementKey	string  		下级 Item 的元素键名
	 * @return	array
	 */
	public function GetItemData( $nParentItem=null, $sChildElementKey=self::KEY_CHILDREN )
	{
		$aModel = $this->GetGtkModel() ;
		JCAT_ASSERT::ASSERT_INSTANCE($aModel,'GtkTreeModel');
		
		$arrRet = array() ;
		
		$aIterator = new JCAT_GtkTreeItemIterator($aModel,$nParentItem,0) ;
		while( !$aIterator->IsDone() )
		{
			$aItem = $aIterator->Current() ;
			
			// 递归子Item
			$arrItem[$sChildElementKey] = $this->GetItemData($aItem,$sChildElementKey) ;
			
			// 各个 Column 上的值
			$nColumnNum = $aModel->get_n_columns() ;
			for ($nIdx=0;$nIdx<$nColumnNum;$nIdx++)
				$arrItem[$nIdx] = $aModel->get_value($aItem,$nIdx) ;
			
			$arrRet[] = $arrItem ;
			
			// 下一个
			$aIterator->Next() ;
		}
		
		return $arrRet ;
	}

	
	/**
	 * 根据一个 数据数组 来设置 Item
	 * 
	 * @access	public
	 * @param 	$arrItems=null		array			数据数组
	 * @param 	$nParentItem=null	GtkTreeIter		上级 Item
	 * @param 	$sChildElementKey	string  		下级 Item 的元素键名
	 * @return	array
	 */
	public function SetItemData( array $arrItems ,$nParentItem=null, $sChildElementKey='children' )
	{
		$aModel = $this->GetGtkModel() ;
		JCAT_ASSERT::ASSERT_INSTANCE($aModel,'GtkTreeStore');
		
		// 列数量
		$nColumnNum = $aModel->get_n_columns() ;
		
		// 插入各行内容
		foreach ($arrItems as $arrOneItem)
		{
			if( !is_array($arrOneItem) )
			{
				throw new JCAT_Exception(JCAT_Language::SentenceEx('正在设置的 UICtrl 数据结构，与 UICtrl 的模型结构不符。','JCAT',null),__macro_exception_code__) ;
			}
			
			// 下级 Items
			if( isset($arrOneItem[$sChildElementKey]) )
			{
				$arrChildren = $arrOneItem[$sChildElementKey] ;
				unset($arrOneItem[$sChildElementKey]) ;
			}
			else
				$arrChildren = array() ;

			$nItemColumnNum = count($arrOneItem) ;
			if( $nItemColumnNum!==$nColumnNum )
			{
				throw new JCAT_Exception(JCAT_Language::SentenceEx('正在设置的 UICtrl 数据结构，与 UICtrl 的模型结构不符。模型为 %d 列，设置的数据为 %d 项。','JCAT',null,$nColumnNum,$nItemColumnNum),__macro_exception_code__) ;
			}
			
			// 插入到模型中
			$aItem = $aModel->append($nParentItem,$arrOneItem) ;
			
			// 递归加载下级 Item
			if( count($arrChildren) )
			{
				$this->SetItemData($arrChildren,$aItem,$sChildElementKey) ;
			}
		}
		
	}

	/**
	 * 初始化  GtkTreeView 的列
	 * 
	 * @access	public
	 * @return	void
	 */
	abstract public function InitializeColumns() ;
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$nClmIdx	int		what's this
	 * @return	GtkTreeViewColumn,null
	 */
	public function GetColumn($nClmIdx)
	{
		JCAT_ASSERT::ASSERT_INT($nClmIdx) ;
		
		$wndMainWidget = $this->GetMainWidget() ;
		JCAT_ASSERT::ASSERT_INSTANCE($wndMainWidget,'GtkTreeView',JCAT_Language::SentenceEx('UICtrl(%s) 的主窗口尚未初始化。','JCAT',null,$this->GetName())) ;
		
		return $wndMainWidget->get_column($nClmIdx) ;
	}
	
	
	/**
	 * 取得 某个 Column 上的 GtkCellRenderer 对象
	 * 
	 * @access	public
	 * @param	$nClmIdx		int		what's this
	 * @param	$nRenderIdx=0	int		what's this
	 * @return	GtkCellRenderer,null
	 */
	public function GetCellRender($nClmIdx,$nRenderIdx=0)
	{
		JCAT_ASSERT::ASSERT_INT($nRenderIdx) ;
		
		$wndColumn = $this->GetColumn($nClmIdx) ;
		if(!$wndColumn)
		{
			return null ;
		}
		
		JCAT_ASSERT::ASSERT_INSTANCE($wndColumn,'GtkTreeViewColumn') ;
		$arrRenders = $wndColumn->get_cell_renderers() ;
		
		return isset($arrRenders[$nRenderIdx])? $arrRenders[$nRenderIdx]: null ;
	}
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$PathOrItem		GtkTreeIter, string		what's this
	 * @param	$nClmIdx		int						what's this
	 * @return	void
	 */
	public function EditCell($PathOrItem,$nClmIdx)
	{
		JCAT_ASSERT::ASSERT_ISTHESE($PathOrItem,array('GtkTreeIter','string'));
		
		// Item
		if( is_object($PathOrItem) )
		{
			$aModel = $this->GetGtkModel() ;
			JCAT_ASSERT::ASSERT_INSTANCE($aModel,'GtkTreeModel') ;
			
			$sPath = $aModel->get_string_from_iter($PathOrItem) ;
		}
		else
		{
			$sPath = $PathOrItem ;
		}
		
		
		// 列
		$wndColumn = $this->GetColumn($nClmIdx) ;
		JCAT_ASSERT::ASSERT_INSTANCE($wndColumn,'GtkTreeViewColumn') ;
		
		// tree 视图
		$wndMainWidget = $this->GetMainWidget() ;
		JCAT_ASSERT::ASSERT_INSTANCE($wndMainWidget,'GtkTreeView',JCAT_Language::SentenceEx('UICtrl(%s) 的主窗口尚未初始化。','JCAT',null,$this->GetName())) ;
		
		// 设置编辑
		$wndMainWidget->set_cursor_on_cell($sPath,$wndColumn,null,true) ;
	}
	

	/**
	 * 查询下一个 item
	 * 
	 * @access	public
	 * @param	$aItem	GtkTreeIter			what's this
	 * @return	GtkTreeIter, null
	 */
	public function GetNextItem(GtkTreeIter $aItem)
	{
		$aModel = $this->GetGtkModel() ;
		if(!$aModel)
		{
			return null ;
		}
		
		JCAT_ASSERT::ASSERT_($aModel->iter_is_valid($aItem),JCAT_Language::SentenceEx('参数 $aItem 必须为Model内有效的Item','JCAT',null)) ;
		
		$aModel->iter_next($aItem) ;		
	}
	
	/**
	 * 查询前一个 item
	 * 
	 * @access	public
	 * @param	$aItem	GtkTreeIter			what's this
	 * @return	GtkTreeIter, null
	 */
	public function GetPreviousItem(GtkTreeIter $aItem)
	{
		$aModel = $this->GetGtkModel() ;
		if(!$aModel)
		{
			return null ;
		}
		
		JCAT_ASSERT::ASSERT_($aModel->iter_is_valid($aItem),JCAT_Language::SentenceEx('参数 $aItem 必须为Model内有效的Item','JCAT',null)) ;
		
		$sPath = $aModel->get_string_from_iter($aItem) ;
		$arrPath = explode(':',$sPath) ;
		
		$nDepthestIdx = count($arrPath) - 1 ;
		
		// 传入的  已经是第一项
		if( $arrPath[$nDepthestIdx]<=0 )
		{
			return null ;
		}
		
		$arrPath[$nDepthestIdx] -- ;
		
		
		return $aModel->get_iter_from_string( implode(':',$arrPath) ) ;		
	}
	
	
	/**
	 * 查询父 item
	 * 
	 * @access	public
	 * @param	$aItem	GtkTreeIter			what's this
	 * @return	GtkTreeIter, null
	 */
	public function GetParentItem(GtkTreeIter $aItem)
	{
		$aModel = $this->GetGtkModel() ;
		if(!$aModel)
		{
			return null ;
		}
		
		JCAT_ASSERT::ASSERT_($aModel->iter_is_valid($aItem),JCAT_Language::SentenceEx('参数 $aItem 必须为Model内有效的Item','JCAT',null)) ;
		
		$sPath = $aModel->get_string_from_iter($aItem) ;
		$arrPath = explode(':',$sPath) ;
		
		if(count($arrPath)===1)
		{
			return null ;
		}
		
		else 
		{
			array_pop($arrPath) ;
			$sPath = implode(':',$arrPath) ;
			
			return $aModel->get_iter_from_string($sPath) ;
		}
	}
	
	
	
	/**
	 * 取回 第一项 Item
	 * 
	 * @access	public
	 * @param	$aItem				GtkTreeIter		what's this
	 * @param	$bForBrother=true	bool			what's this
	 * @return	GtkTreeIter, null
	 */
	public function GetFirstItem(GtkTreeIter $aItem=null,$bForBrother=true)
	{
		return $this->GetextremityItem($aItem,$bForBrother) ;
	}
	
	
	/**
	 * 取回 最后一项 Item
	 * 
	 * @access	public
	 * @param	$aItem				GtkTreeIter		what's this
	 * @param	$bForBrother=true	bool			what's this
	 * @return	GtkTreeIter, null
	 */
	public function GetLastItem(GtkTreeIter $aItem=null,$bForBrother=true)
	{
		return $this->GetextremityItem($aItem,$bForBrother,false) ;
	}

	
	/**
	 * 获得两端的 Item
	 * 
	 * @access	private
	 * @param	$aItem				GtkTreeIter		what's this
	 * @param	$bForBrother=true	bool			what's this
	 * @param	$bBegin=true		bool			what's this
	 * @return	GtkTreeIter, null
	 */
	private function GetextremityItem(GtkTreeIter $aItem=null,$bForBrother=true,$bBegin=true)
	{
		$aModel = $this->GetGtkModel() ;
		if(!$aModel)
		{
			return null ;
		}
		JCAT_ASSERT::ASSERT_( ($aItem===null or $aModel->iter_is_valid($aItem)),JCAT_Language::SentenceEx('参数 $aItem 必须为Model内有效的Item','JCAT',null)) ;
		
		// 没有 Item
		$nItemCnt = $aModel->iter_n_children($aItem) ;
		if($nItemCnt<=0)
		{
			return null ;
		}
		
		// 父 item
		if($bForBrother)
		{
			$aParentItem = $this->GetParentItem($aItem) ;
		}
		
		else
		{
			$aParentItem = $aItem ;
		}

		// 父item 的  path
		if($aParentItem)
		{
			$sPath = $aModel->get_string_from_iter($aParentItem) ;
			$arrPath = explode(':',$sPath) ;
		}
		else
		{
			$arrPath = array() ;
		}
		
		// last or first item 的 path
		if($bBegin)
		{
			$arrPath[] = '0' ;
		}
		else 
		{
			$arrPath[] = $nItemCnt-1 ;			
		}
		
		// 返回
		return $aModel->get_iter( implode(':',$arrPath) ) ;		
	}
	
	
	/**
	 * 根据 Item Path 返回 Item
	 * 
	 * @access	public
	 * @param	$Path		sting,array			what's this
	 * @return	GtkTreeIter
	 */
	public function GetItem($Path)
	{
		JCAT_ASSERT::ASSERT_ISTHESE($Path,array('string','array:int'));
		if(is_array($Path))
		{
			$sPath = implode(':',$Path) ;
		}
		else
		{
			$sPath = $Path ;
		}
		
		$aModel = $this->GetGtkModel() ;
		if( $aModel )
		{
			return $aModel->get_iter($sPath) ;
		}
		else 
		{
			return null ;
		}
	}

	/**
	 * 返回指定 Item 的 Path
	 * 
	 * @access	public
	 * @param	$aItem		GtkTreeIter			what's this
	 * @return	string
	 */
	public function GetItemPath(GtkTreeIter $aItem)
	{
		$aModel = $this->GetGtkModel() ;
		if(!$aModel)
		{
			return null ;
		}
		JCAT_ASSERT::ASSERT_( $aModel->iter_is_valid($aItem),JCAT_Language::SentenceEx('参数 $aItem 必须为Model内有效的Item','JCAT',null)) ;
		return $aModel->get_string_from_iter($aItem) ;
	}
	
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$arrCellDatas	array			what's this
	 * @param	$aParent=null	GtkTreeIter		what's this
	 * @return	GtkTreeIter
	 */
	public function AppendItem(array $arrCellDatas,GtkTreeIter $aParent=null)
	{
		$aModel = $this->GetGtkModel() ;
		if(!$aModel)
		{
			return null ;
		}
		
		return $aModel->append($aParent,$arrCellDatas) ;
	}
	
	/**
	 * 返回一项数据
	 * 
	 * @access	public
	 * @param	$aItem		GtkTreeIter			what's this
	 * @param	$nColumn	int					what's this
	 * @return	mixed
	 */
	public function GetCellData(GtkTreeIter $aItem,$nColumn)
	{
		JCAT_ASSERT::ASSERT_INT($nColumn) ;
		
		$aModel = $this->GetGtkModel() ;
		if(!$aModel)
		{
			return null ;
		}
		JCAT_ASSERT::ASSERT_( $aModel->iter_is_valid($aItem),JCAT_Language::SentenceEx('参数 $aItem 必须为Model内有效的Item','JCAT',null)) ;
		
		return $aModel->get_value($aItem,$nColumn) ;
	}
	
	/**
	 * 设置一项数据
	 * 
	 * @access	public
	 * @param	$aItem		GtkTreeIter			what's this
	 * @param	$nColumn	int					what's this
	 * @param	$Value		mixed				what's this
	 * @return	mixed
	 */
	public function SetCellData(GtkTreeIter $aItem,$nColumn,$Value)
	{
		JCAT_ASSERT::ASSERT_INT($nColumn) ;
		
		$aModel = $this->GetGtkModel() ;
		if(!$aModel)
		{
			return null ;
		}
		JCAT_ASSERT::ASSERT_( $aModel->iter_is_valid($aItem),JCAT_Language::SentenceEx('参数 $aItem 必须为Model内有效的Item','JCAT',null)) ;
		
		$aModel->set($aItem,$nColumn,$Value) ;
	}
	
	/**
	 * 删除一行 Item
	 * 
	 * @access	public
	 * @param	$aItem		GtkTreeIter			what's this
	 * @return	void
	 */
	public function RemoveItem(GtkTreeIter $aItem)
	{
		$aModel = $this->GetGtkModel() ;
		if(!$aModel)
		{
			return ;
		}
		JCAT_ASSERT::ASSERT_( $aModel->iter_is_valid($aItem),JCAT_Language::SentenceEx('参数 $aItem 必须为Model内有效的Item','JCAT',null)) ;
		
		$aModel->remove($aItem) ;
	}
	
	/**
	 * 删除所有行
	 *
	 * @access	public
	 * @return	void
	 */
	public function RemoveAllItem()
	{
		$aModel = $this->GetGtkModel() ;
		$aModel->clear() ;
	}
	
	/**
	 * 判断两个 item 是否相同
	 * 
	 * @access	public
	 * @param	$aItemA		GtkTreeIter	what's this
	 * @param	$aItemB		GtkTreeIter	what's this
	 * @return	bool
	 */
	public function IsSameItem(GtkTreeIter $aItemA,GtkTreeIter $aItemB)
	{
		$aModel = $this->GetGtkModel() ;
		if(!$aModel)
		{
			return false ;
		}
		
		if( !$aModel->iter_is_valid($aItemA) )
		{
			return false ;
		}
		
		if( !$aModel->iter_is_valid($aItemB) )
		{
			return false ;
		}
		
		return	$aModel->get_string_from_iter($aItemA)
					== $aModel->get_string_from_iter($aItemB) ;
	}
	
	
	
	/**
	 * 取得第一项被选中的Item
	 * 
	 * @access	public
	 * @return	void
	 */
	public function GetFirstSelectedItem()
	{
		$aWidget = $this->GetMainWidget() ;
		JCAT_ASSERT::ASSERT_INSTANCE($aWidget,'GtkTreeView',JCAT_Language::SentenceEx('UICtrl(%s) 的主窗口尚未初始化。','JCAT',null,$this->GetName())) ;
		
		$aSelection = $aWidget->get_selection() ;
		list($aModel, $aItem) = $aSelection->get_selected() ;
		return $aItem ;
	}
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$aRenderer		GtkCellRendererToggle	what's this
	 * @param	$sPath			string					what's this
	 * @param	$nColumn		int						what's this
	 * @return	void
	 */
	public function OnActiveToggled( GtkCellRendererToggle $aRenderer , $sPath, $nColumn )
	{
		JCAT_ASSERT::ASSERT_INT($nColumn) ;
		
		// 其他 处理函数 ==========================

		// 事件参数
		$arrArgvs = func_get_args() ;
		$arrArgvs[] = $this ;
		
		// 事件 接收对象 
		$arrArgvs[] = $this ;

		// 事件名称
		$sWidgetId = $this->GetMainWidgetId() ;
		$sEventName = $sWidgetId.'-'.'toggled' ;
		$arrArgvs[] = $sEventName ;
		
		// 调用已注册的 事件处理
		call_user_func_array(array('JCAT_EventProcessor','EventTransmitForGtkSignal'),$arrArgvs) ;

		// 切换状态
		$aModel = $this->GetGtkModel() ;
		$aItem = $aModel->get_iter_from_string($sPath) ;
		$aModel->set($aItem,$nColumn,!$aModel->get_value($aItem,$nColumn)) ;
	}
		
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$aRenderer		GtkCellRendererText		what's this
	 * @param	$sPath			string					what's this
	 * @param	$sNewText		string					what's this
	 * @param	$nColumn		int						what's this
	 * @return	void
	 */
	public function OnTextEdit( GtkCellRendererText $aRenderer , $sPath, $sNewText, $nColumn )
	{
		if($sNewText===null)
			$sNewText = '' ;
		JCAT_ASSERT::ASSERT_STRING($sNewText) ;
		JCAT_ASSERT::ASSERT_INT($nColumn) ;
		
		// 其他 处理函数 ==========================

		// 事件参数
		$arrArgvs = func_get_args() ;
		$arrArgvs[] = $this ;

		// 事件 接收对象 
		$arrArgvs[] = $this ;

		// 事件名称
		$sWidgetId = $this->GetMainWidgetId() ;
		$sEventName = $sWidgetId.'-'.'edited' ;
		$arrArgvs[] = $sEventName ;
		
		// 调用已注册的 事件处理
		call_user_func_array(array('JCAT_EventProcessor','EventTransmitForGtkSignal'),$arrArgvs) ;

		// 使用新的数据
		$aModel = $this->GetGtkModel() ;
		$aItem = $aModel->get_iter_from_string($sPath) ;
		$aModel->set($aItem,$nColumn,$sNewText) ;
	}

	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$sCellRenderer		GtkCellRenderer			what's this
	 * @param	$wndEditable		GtkCellEditable			what's this
	 * @param	$sPath				string					what's this
	 * @param	$nColumn=-1		int						what's this
	 * @return	void
	 */
	public function OnTextEditStarted( GtkCellRenderer $sCellRenderer, GtkCellEditable $wndEditable, $sPath, $nColumn=-1 )
	{
		// Nothing to do ... ...
	}
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$sCellRenderer		GtkCellRenderer			what's this
	 * @param	$nColumn=-1		int						what's this
	 * @return	void
	 */
	public function OnTextEditCanceled( GtkCellRenderer $sCellRenderer,$nColumn=-1 )
	{
		// Nothing to do ... ...
	}
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @return	void
	 */
	public function OnRenderPixbuf(GtkCellLayout $wndCellLayout, GtkCellRenderer $aRenderer, GtkTreeModel $aModel, GtkTreeIter $aItem, $nClm)
	{
		JCAT_ASSERT::ASSERT_INT($nClm);
		$sImagePath = $aModel->get_value($aItem,$nClm) ;
		
		$aImage = self::GetImageForItem($sImagePath) ;
		$aRenderer->set_property('pixbuf', $aImage);		
	}
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @return	GdkPixbuf
	 * @static 
	 */
	static protected function GetImageForItem($sImgPath)
	{
		// 确定路径
		if( is_file($sImgPath) )
		{
			$sUsePath = $sImgPath ;
		}
		
		// 缺省图片路径
		else 
		{
			$sUsePath = JCATPATH.self::UNKONW_IMAGE ;
		}
		
		// 整理路径
		$sImgTidyPath = JCAT_Global::TidyPath($sUsePath) ;
		
		// 创建 GdkPixbuf 对象
		if( !isset(self::$arrImgForItems[$sImgTidyPath]) )
		{
			self::$arrImgForItems[$sImgTidyPath] = GdkPixbuf::new_from_file($sImgTidyPath) ;
		}
		
		// 返回
		return self::$arrImgForItems[$sImgTidyPath] ;
	}
	
	// 属性 ///////////////////////////////////////////////////////////////////////////////

	const KEY_CHILDREN = 'children' ;
	
	const UNKONW_IMAGE = 'src/Image/TreeItemIcon_Unkonw_24x24.png' ;
	
	const TOP_ITEM = null ;
	
	static private $arrImgForItems = array() ;
}


?>